#include <iostream>
#include <vector>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>


template <class T>
class RingQueue
{
private:
    // 申请资源
    void P(sem_t* sem) 
    {
        sem_wait(sem);
    }

    // 释放资源
    void V(sem_t* sem) 
    {
        sem_post(sem);
    }
public:
    RingQueue(size_t capacity)
        : capacity_(capacity), in_(0), out_(0), buffer_(std::vector<T>(capacity)) // 初始化的顺序为变量声明顺序，而非初始化列表的顺序
    {
        pthread_mutex_init(&mutex_, NULL);
        sem_init(&empty_, 0, capacity);
        sem_init(&full_, 0, 0);
    }

    void put(T item) 
    {
        P(&empty_); // 申请资源
        pthread_mutex_lock(&mutex_);

        buffer_[in_++] = item;
        in_ %= capacity_;

        pthread_mutex_unlock(&mutex_);
        V(&full_); // 释放资源
    }

    // T get()
    // {
    //     P(&full_); // 申请资源
    //     pthread_mutex_lock(&mutex_);

    //     T item = buffer_[out_++];
    //     out_ %= capacity_;

    //     pthread_mutex_unlock(&mutex_);
    //     V(&empty_); // 释放资源

    //     return item;
    // }

    T get()
    {
        P(&full_); // 申请资源
        pthread_mutex_lock(&mutex_);

        T item = buffer_[out_++];
        out_ %= capacity_;

        pthread_mutex_unlock(&mutex_);
        V(&empty_); // 释放资源

        return item;
    }

    ~RingQueue()
    {
        pthread_mutex_destroy(&mutex_);
        sem_destroy(&empty_);
        sem_destroy(&full_);
    }

private:
    std::vector<T> buffer_;
    size_t capacity_;
    size_t in_;
    size_t out_;

    pthread_mutex_t mutex_;
    sem_t full_;
    sem_t empty_;
};

const int PRODUCER_NUMS = 3;
const int CONSUMER_NUMS = 2;

typedef struct 
{
    RingQueue<int>* rq;
    int id;
} producer_t;

typedef struct 
{
    RingQueue<int>* rq;
    int id;
} consumer_t;

void* produce(void* arg)
{
    producer_t* producer = static_cast<producer_t*>(arg);
    int item = 0;
    while (1) {
        producer->rq->put(item);
        std::cout << "producer-" << producer->id << ": " << item++ << std::endl;
        sleep(1);
    }
    delete producer;
    return NULL;
}

void* consume(void* arg)
{
    consumer_t* consumer = static_cast<consumer_t*>(arg);
    while (1) {
        int item = consumer->rq->get();
        std::cout << "consumer-" << consumer->id << ": " << item << std::endl;
        sleep(1);
    }
    delete consumer;
    return NULL;
}

int main()
{
    RingQueue<int>* rq = new RingQueue<int>(6);

    pthread_t producers[PRODUCER_NUMS];
    pthread_t consumers[CONSUMER_NUMS];

    for (int i = 0; i < PRODUCER_NUMS; i++) {
        producer_t* producer = new producer_t();
        producer->rq = rq;
        producer->id = i;

        pthread_create(&producers[i], NULL, produce, producer);
        sleep(1);
    }

    for (int i = 0; i < CONSUMER_NUMS; i++) {
        consumer_t* consumer = new consumer_t();
        consumer->rq = rq;
        consumer->id = i;

        pthread_create(&consumers[i], NULL, consume, consumer);
    }

    // 等待线程结束，释放资源
    for (int i = 0; i < PRODUCER_NUMS; i++) {
        pthread_join(producers[i], NULL);
    }

    for (int i = 0; i < CONSUMER_NUMS; i++) {
        pthread_join(consumers[i], NULL);
    }

    delete rq;

    return 0;
}


// #include <iostream>
// #include <vector>
// #include <pthread.h>
// #include <semaphore.h>
// #include <unistd.h>


// template <class T>
// class RingQueue
// {
// public:
//     RingQueue(size_t capacity) 
//         : buffer_(std::vector<T>(capacity)), in_(0), out_(0)
//     {
//         sem_init(&empty_, 0, capacity); // 第二个参数 pshared = 0 -- 进程级别共享
//         sem_init(&full_, 0, 0);
//         pthread_mutex_init(&mutex_, NULL);
//     }

//     void put(T item) 
//     {
//         // 申请资源
//         sem_wait(&empty_);
//         pthread_mutex_lock(&mutex_);

//         buffer_[in_] = item;
//         in_ = (in_ + 1) % buffer_.size();

//         pthread_mutex_unlock(&mutex_);
//         // 释放资源
//         sem_post(&full_);
//     }

//     T get() 
//     {
//         // 申请资源
//         sem_wait(&full_);
//         pthread_mutex_lock(&mutex_);

//         T item = buffer_[out_];
//         out_ = (out_ + 1) % buffer_.size();

//         pthread_mutex_unlock(&mutex_);
//         // 释放资源
//         sem_post(&empty_);

//         return item;
//     }

//     ~RingQueue() 
//     {
//         sem_destroy(&empty_);
//         sem_destroy(&full_);
//         pthread_mutex_destroy(&mutex_);
//     }
// private:
//     sem_t empty_;
//     sem_t full_;
//     pthread_mutex_t mutex_;

//     std::vector<T> buffer_;
//     size_t in_;
//     size_t out_;
// };

// void* produce(void* arg) 
// {
//     RingQueue<int>* rq = static_cast<RingQueue<int>*>(arg);
//     int item = 0;

//     while (true) {
//         rq->put(item);
//         std::cout << "produce: " << item++ << std::endl;
//         sleep(1);
//     }
//     return NULL;
// }

// void* consume(void* arg) 
// {
//     RingQueue<int>* rq = static_cast<RingQueue<int>*>(arg);
//     while (true) {
//         int item = rq->get();
//         std::cout << "consume: " << item << std::endl;
//         sleep(1);
//     }
//     return NULL;
// }

// int main()
// {
//     RingQueue<int>* rq = new RingQueue<int>(10);

//     pthread_t producer;
//     pthread_t consumer;

//     pthread_create(&producer, NULL, produce, rq);
//     pthread_create(&consumer, NULL, consume, rq);

//     pthread_join(producer, NULL);
//     pthread_join(consumer, NULL);

//     delete rq;

//     return 0;
// }